//
//  BCDownloadHelper.m
//  断点上传和下载
//
//  Created by aaaa on 2020/3/19.
//  Copyright © 2020 aaaa. All rights reserved.
//

#import "BCDownloadHelper.h"
#import <AFNetworking/AFNetworking.h>

@interface BCDownloadHelper ()

@property(nonatomic,strong)NSDictionary *taskMap;

@end
@implementation BCDownloadHelper
static BCDownloadHelper *helper = nil;

+ (instancetype)defaultHelper {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        helper = [[BCDownloadHelper alloc] init];
    });
    return helper;
}

#pragma mark - 任务操作相关 -
+(NSURLSessionDownloadTask *)downloadWithUrl:(NSURL *)url
                                    progress:(void(^)(NSUInteger currentLength,NSUInteger totalLength))progress result:(void(^)(BOOL isSuccess,NSError *error))result
{

    if ((url && url.absoluteString.length == 0) || ![url isKindOfClass:[NSURL class]]) {
        return nil;
    }
    
    NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    configuration.timeoutIntervalForRequest = 3600;//一小时后过期
    AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] initWithSessionConfiguration:configuration];
    manager.responseSerializer.acceptableContentTypes = [NSSet setWithObject:@"video/mp4"];
    __block NSFileHandle *fileHandle;
    NSString *cachePath = [self getFileCachePathWithUrl:url.absoluteString];
    __block NSUInteger currentFileLength  = [self getCacheFileLengthWithUrl:url.absoluteString];
    __block NSUInteger fileTotalLength = 0;
    
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    // 设置HTTP请求头中的Range
    NSString *range = [NSString stringWithFormat:@"bytes=%zd-", currentFileLength];
    [request setValue:range forHTTPHeaderField:@"Range"];
        
    NSURLSessionDownloadTask *_downloadTask = [manager dataTaskWithRequest:request uploadProgress:nil downloadProgress:nil completionHandler:^(NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error) {

        NSLog(@"download finish %lld curentlength = %lu totalLength = %lld",response.expectedContentLength,(unsigned long)currentFileLength,fileTotalLength);
        
        // 关闭fileHandle
        [fileHandle closeFile];
        fileHandle = nil;
                
        if (error && (currentFileLength != fileTotalLength) ) {
            //错误
            [[NSFileManager defaultManager] removeItemAtPath:cachePath error:nil];
            result(NO,error);
        }else{
            NSString *localPath = [BCDownloadHelper getFileLocalPathWithUrl:url.absoluteString];
            NSError *err;
            [[NSFileManager defaultManager] moveItemAtPath:cachePath toPath:localPath error:&err];
            NSLog(@"err %@",err);
            result(YES,nil);
        }
    }];
    
    //服务器会返回剩余需要下载的文件长度
    [manager setDataTaskDidReceiveResponseBlock:^NSURLSessionResponseDisposition(NSURLSession * _Nonnull session, NSURLSessionDataTask * _Nonnull dataTask, NSURLResponse * _Nonnull response) {
        NSLog(@"NSURLSessionResponseDisposition");
        // 获得下载文件的总长度：请求下载的文件长度 + 当前已经下载的文件长度
        fileTotalLength = response.expectedContentLength + currentFileLength;
        fileHandle = [NSFileHandle fileHandleForWritingAtPath:cachePath];
        // 允许处理服务器的响应，才会继续接收服务器返回的数据
        return NSURLSessionResponseAllow;
    }];
    
    [manager setDataTaskDidReceiveDataBlock:^(NSURLSession * _Nonnull session, NSURLSessionDataTask * _Nonnull dataTask, NSData * _Nonnull data) {
        // 指定数据的写入位置(文件内容的最后面)
        [fileHandle seekToEndOfFile];
        // 继续写入数据
        [fileHandle writeData:data];
        // 拼接文件总长度
        currentFileLength += data.length;
        dispatch_sync(dispatch_get_main_queue(), ^{
            // 下载进度
            if (fileTotalLength == 0) {
                NSLog(@"文件长度为0");
                !progress ? : progress(0,0);
            } else {
                !progress ? : progress(currentFileLength,fileTotalLength);
            }
        });
    }];
    [[BCDownloadHelper defaultHelper].taskMap setValue:_downloadTask forKey:url.absoluteString];
    return _downloadTask;
}


//取消下载
+ (void)cancleTaskWithUrl:(NSURL *)url{
    if (url && [[BCDownloadHelper defaultHelper].taskMap.allKeys containsObject:url.absoluteString]) {
        NSURLSessionDownloadTask *task = [[BCDownloadHelper defaultHelper].taskMap objectForKey:url.absoluteString];
        //移除缓存
        [[NSFileManager defaultManager] removeItemAtPath:[BCDownloadHelper getFileCachePathWithUrl:url.absoluteString] error:nil];
        [task cancel];
        NSLog(@"%ld",task.state);
    }
}

//暂停下载
+ (void)pauseTaskWithUrl:(NSURL *)url{
    if (url && [[BCDownloadHelper defaultHelper].taskMap.allKeys containsObject:url.absoluteString]) {
        NSURLSessionDownloadTask *task = [[BCDownloadHelper defaultHelper].taskMap objectForKey:url.absoluteString];
        [task suspend];
        NSLog(@"暂停 当前下载的长度为 ： %lu",[BCDownloadHelper getCacheFileLengthWithUrl:url.absoluteString]);
    }
}

//开始下载
+ (void)resumeTaskWithUrl:(NSURL *)url{
    if (url && [[BCDownloadHelper defaultHelper].taskMap.allKeys containsObject:url.absoluteString]) {
        NSURLSessionDownloadTask *task = [[BCDownloadHelper defaultHelper].taskMap objectForKey:url.absoluteString];
        [task resume];
    }
}

#pragma mark - 文件信息相关 -
/// 获取文件保存路径
+ (NSString *)getFileLocalPathWithUrl:(NSString *)fileUrl{
    // 沙盒文件路径
    NSString *path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject] stringByAppendingPathComponent:fileUrl.lastPathComponent];
    NSLog(@"File move to: %@",path);
    return path;
}

////获取缓存文件的路径
+ (NSString *)getFileCachePathWithUrl:(NSString *)fileUrl{
    // 沙盒文件路径
    NSString *path = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"Bcircle/Image"];
    BOOL isDir = NO;
    BOOL existed = [[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isDir];
    if(!isDir && !existed){
        [[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
    }
    path = [path stringByAppendingPathComponent:fileUrl.lastPathComponent];
    NSLog(@"File Cache to: %@",path);
    NSFileManager *manager = [NSFileManager defaultManager];
    if (![manager fileExistsAtPath:path]) {
        // 如果没有下载文件的话，就创建一个文件。如果有下载文件的话，则不用重新创建(不然会覆盖掉之前的文件)
        [manager createFileAtPath:path contents:nil attributes:nil];
    }
    return path;
}

//获取缓存文件的大小
+ (NSInteger)getCacheFileLengthWithUrl:(NSString *)url{
    NSString *path = [BCDownloadHelper getFileCachePathWithUrl:url];
    NSInteger fileLength = 0;
    NSFileManager *fileManager = [[NSFileManager alloc] init];
    if ([fileManager fileExistsAtPath:path]) {
        NSError *error = nil;
        NSDictionary *fileDict = [fileManager attributesOfItemAtPath:path error:&error];
        if (!error && fileDict) {
            fileLength = [fileDict fileSize];
        }
    }
    return fileLength;
}


#pragma mark - getter -
-(NSDictionary *)taskMap{
    if (!_taskMap) {
        _taskMap = @{}.mutableCopy;
    }
    return _taskMap;
}
@end
